using System;
using System.Collections.Generic;

namespace WenYu.Core.CodeGen
{
    /// <summary>
    /// 中间代码(IR)指令
    /// 
    /// 结构: [操作码] [操作数...]
    /// - 操作码: 指定操作类型
    /// - 操作数: 0个或多个参数（如变量名、常量值、跳转地址等）
    /// 
    /// 示例:
    /// - LOAD_INT 10              加载整数10
    /// - STORE_VAR "x"            存储到变量x
    /// - ADD                       执行加法
    /// - PRINT 1                   输出1个值
    /// 
    /// 对标需求: REQ-04 代码生成器
    /// </summary>
    public class IRInstruction
    {
        /// <summary>操作码</summary>
        public IROpcode Opcode { get; set; }
        
        /// <summary>操作数数组（可为空）</summary>
        public object[] Operands { get; set; }
        
        /// <summary>源代码行号（用于错误报告）</summary>
        public int LineNumber { get; set; }
        
        /// <summary>调试注释</summary>
        public string Comment { get; set; }
        
        /// <summary>初始化新指令（推荐使用）</summary>
        public IRInstruction(IROpcode opcode, params object[] operands)
        {
            Opcode = opcode;
            Operands = operands ?? Array.Empty<object>();
            LineNumber = -1;  // 默认未设置
            Comment = string.Empty;
        }
        
        /// <summary>
        /// 从字符串解析指令
        /// 用于调试和代码分析
        /// 
        /// 格式: "操作码 操作数..."
        /// 示例: "LOAD_INT 10" → IRInstruction(IROpcode.LOAD_INT, 10)
        /// </summary>
        public static IRInstruction Parse(string irCode)
        {
            if (string.IsNullOrWhiteSpace(irCode))
                throw new ArgumentException("IR代码不能为空");
            
            var parts = irCode.Trim().Split(' ');
            if (parts.Length == 0)
                throw new ArgumentException("无效的IR代码");
            
            if (!Enum.TryParse<IROpcode>(parts[0], out var opcode))
                throw new ArgumentException($"未知的操作码: {parts[0]}");
            
            // 剩余部分作为操作数
            var operands = new List<object>();
            for (int i = 1; i < parts.Length; i++)
            {
                // 尝试解析为不同类型
                if (int.TryParse(parts[i], out var intVal))
                    operands.Add(intVal);
                else if (double.TryParse(parts[i], out var doubleVal))
                    operands.Add(doubleVal);
                else if (parts[i].StartsWith("\"") && parts[i].EndsWith("\""))
                    operands.Add(parts[i].Substring(1, parts[i].Length - 2));
                else
                    operands.Add(parts[i]);  // 作为字符串
            }
            
            return new IRInstruction(opcode, operands.ToArray());
        }
        
        /// <summary>获取操作数个数</summary>
        public int OperandCount => Operands?.Length ?? 0;
        
        /// <summary>获取指定索引的操作数</summary>
        public object GetOperand(int index)
        {
            if (index < 0 || index >= OperandCount)
                throw new IndexOutOfRangeException($"操作数索引超出范围: {index}");
            return Operands[index];
        }
        
        /// <summary>获取指定索引的操作数作为字符串</summary>
        public string GetOperandAsString(int index)
        {
            return GetOperand(index)?.ToString() ?? string.Empty;
        }
        
        /// <summary>获取指定索引的操作数作为整数</summary>
        public int GetOperandAsInt(int index)
        {
            var op = GetOperand(index);
            if (op is int intVal)
                return intVal;
            if (int.TryParse(op.ToString(), out intVal))
                return intVal;
            throw new InvalidOperationException($"无法将操作数转换为整数: {op}");
        }
        
        /// <summary>转换为字符串（便于调试）</summary>
        public override string ToString()
        {
            if (OperandCount == 0)
                return Opcode.ToString();
            
            var operandStr = string.Join(" ", Operands);
            
            if (string.IsNullOrEmpty(Comment))
                return $"{Opcode} {operandStr}";
            else
                return $"{Opcode} {operandStr}  ; {Comment}";
        }
        
        /// <summary>创建一个带注释的副本</summary>
        public IRInstruction WithComment(string comment)
        {
            return new IRInstruction(Opcode, Operands)
            {
                LineNumber = this.LineNumber,
                Comment = comment
            };
        }
    }
}
